package com.geek.water.security;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.geek.water.constant.MessageConstant;
import com.geek.water.constant.RedisTokenConstant;
import com.geek.water.entity.User;
import com.geek.water.exception.AccessTokenInvalidException;
import com.geek.water.exception.HealthException;
import com.geek.water.utils.JwtHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author chenmin
 * @desc TODO
 * @date 2025/8/11
 */
@Slf4j
@RequiredArgsConstructor
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    //Redis
    private final RedisTemplate<String, Object> redisTemplate;

    //过滤器核心逻辑
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //获取请求路径
        String uri = request.getRequestURI();
        log.info("JwtAuthenticationTokenFilter uri = {}" , uri);
        if(uri.contains("/admin/auth/login")){
            //若是登录操作则直接放行
            filterChain.doFilter(request, response);
            return;
        }

        //1.从请求头中，获取访问token令牌   请求头中设置Token信息  以Authorization作为键，以Bearer accessToken作为值
        String authorization = request.getHeader("Authorization");

        //2.访问令牌为空
        if(StrUtil.isEmpty(authorization)){
            throw new HealthException(MessageConstant.TOKEN_EMPTY);
        }
        String token = authorization.substring(7);
        log.info("JwtAuthenticationTokenFilter token = {}" , token);

        //3.验证访问令牌是否过期
        if(JwtHelper.isExpiration(token)){
            throw new AccessTokenInvalidException(MessageConstant.ACCESS_TOKEN_VERIFY_FAIL);
        }

        //4.验证访问令牌是否合法
        Long userId = JwtHelper.getUserId(token);
        if(userId==null){
            throw new HealthException(MessageConstant.TOKEN_ILLEGAL);
        }

        //5.从Redis中获取当前登录者信息   user::token::1
        Object o = redisTemplate.opsForValue().get(RedisTokenConstant.USER_TOKEN + "::" + userId);
        if(o==null){
            throw new HealthException(MessageConstant.TOKEN_REDIS_NULL);
        }
        User user = JSONUtil.toBean(o.toString(), User.class);

        //6.将认证通过的信息Authentication（用户信息、权限、以认证状态等），存储至认证上下文SecurityContextHolder中
        //User -> LoginUser
        LoginUser loginUser = new LoginUser(user);
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        //放行
        filterChain.doFilter(request, response);
    }
}
